import pyvisa
import pyvisa as visa
import time
import numpy as np
import serial
import vxi11

class InstrumentInitial(object):
    def __init__(self, instr_id):
        self.instr_id = instr_id
        self.rm = visa.ResourceManager()
        self.dev_connect_visa = False
        self.dev_list = self.rm.list_resources()
        self.inst = None
        self.list_connected_devices()

    def instr_initial(self):

        self.inst = self.rm.open_resource('{}'.format(self.instr_id))

    @property
    def F(self):
        return self.inst.query("*IDN?")

    def write_command(self, command):
        self.inst.write(command)

    def query_command(self, command):
        return self.inst.query(command)

    def list_connected_devices(self):
        self.dev_list = self.rm.list_resources()
        self.dev_connect_visa = False
        # 'IP:169.254.174.89'   # 'TCPIP0::169.254.174.89::inst0::INSTR'
        # 'GPIB:2'      # 'GPIB0::12::INSTR'
        if 'IP' in self.instr_id:
            self.instr_id = 'TCPIP0::{}::inst0::INSTR'.format(self.instr_id.split(':')[1])
        elif 'GPIB' in self.instr_id:
            self.instr_id = 'GPIB0::{}::INSTR'.format(self.instr_id.split(':')[1])
        else:
            print(
                "\033[0;37;41mERROR: Unrecognized instrument interface types, only IP and GPIB can be recognized !!\033[0m")

        for dev_ in self.dev_list:
            if self.instr_id in dev_:
                self.dev_connect_visa = True
        if not self.dev_connect_visa:
            print(
                "\033[0;37;41mERROR: The instrument is not linked to VISA !!\033[0m")
# 数字万用表类
# DigitalMultimeterSDM3065X
class DigitalMultimeterSDM3065X:
    def __init__(self, dev_id):
        self.dev_id = dev_id
        self.device = pyvisa.ResourceManager().open_resource(dev_id)
        print(f'设备基本信息：{self.device.query("*IDN?")}')

    def clear_state(self):
        # 清除状态命令。清除所有寄存器组中的事件寄存器。也会清除错误队列。
        self.device.write('*CLS')

    def reset_dev(self):
        # 将仪器恢复为出厂默认状态
        self.device.write('*RST')

    def dc_voltage(self, counts=1, plc=0.005):
        # 等待测量完成并将所有可用的测量结果复制到仪器的输出缓冲区
        self.device.write('CONF:VOLT:DC')
        self.device.write(f'VOLT:DC:NPLC {plc}')
        self.device.write(f'SAMP:COUN {counts}')  # 设置采样次数

        voltage_str = self.device.query('READ?')[:-1]  # 读取本次测量生成的测量值
        voltage_out = [float(voltage) for voltage in voltage_str.split(',')]
        return voltage_out

    def measure_dc_current(self, wait_time=2):
        ret = self.device.query('MEAS:CURR:DC?')
        time.sleep(wait_time)
        current = float(ret.replace('\n', ''))
        return current

    def measure_dc_voltage(self, wait_time=2):
        ret = self.device.query('MEAS:VOLT:DC?')
        time.sleep(wait_time)
        voltage = float(ret.replace('\n', ''))
        return voltage

# 示波器OscilloscopeSDS2504X
class OscilloscopeSDS2504X:
    def __init__(self, dev_id):
        self.dev_id = dev_id
        self.device = pyvisa.ResourceManager().open_resource(dev_id)
        print(f'设备基本信息：{self.device.query("*IDN?")}')

# DP832A
class DP832A:
    def __init__(self, dev_id):
        self.dev_id = dev_id
        self.device = pyvisa.ResourceManager().open_resource(dev_id)
        print(f'设备基本信息：{self.device.query("*IDN?")}')

    def set_voltage_current(self, channel, voltage, current=1):
        self.device.write(f':APPL CH{channel},{voltage},{current}')

    def channel_state(self, channel, state):
        self.device.write(f':OUTP CH{channel},{state.upper()}')

# GPO2303s
class GPO2303s:
    def __init__(self, dev_id):
        self.dev_id = dev_id
        self.device = pyvisa.ResourceManager().open_resource(dev_id)
        print(f'设备基本信息：{self.device.query("*IDN?")}')

    def set_voltage_current(self, channel, voltage, current=1):
        self.device.write(f'VSET{channel}:{round(voltage, 3)}')
        self.device.write(f'ISET{channel}:{current}')

    def channel_state(self, state):
        if 'ON' in state.upper():
            self.device.write('OUT1')
        elif 'OFF' in state.upper():
            self.device.write('OUT0')
        else:
            print("\033[0;37;41mERROR: Command Error !!\033[0m")

# Keysight34461A
class Keysight34461A:
    def __init__(self, dev_id):
        self.dev_id = dev_id
        self.device = pyvisa.ResourceManager().open_resource(dev_id)
        print(f'设备基本信息：{self.device.query("*IDN?")}')

    def clear_state(self):
        # 清除状态命令。清除所有寄存器组中的事件寄存器。也会清除错误队列。
        self.device.write('*CLS')

    def reset_dev(self):
        # 将仪器恢复为出厂默认状态
        self.device.write('*RST')
    def reset_id(self):
        self.device.write("READ?")

    def set_voltage(self, voltage):
        # 设置输出电压
        self.device.write(f'CONF:VOLT:DC {voltage}')
        print(f'设置输出电压为：{voltage}V')

    def dc_voltage(self, counts=1, plc=0.02):
        # 等待 测量完成并将所有可用的测量结果复制到仪器的输出缓冲区
        self.device.write(f'CONF:VOLT:DC {plc}, 0.003')
        self.device.write('VOLT:DC:RANG:AUTO ON')  # 设置电压量程自动调整
        self.device.write('TRIG:SOUR IMM')  # 设置触发源为立即触发
        self.device.write(f'SAMP:COUN {counts}')  # 设置采样次数
        voltage_str = self.device.query('READ?')[:-1]  # 读取本次测量生成的测量值
        voltage_out = [float(voltage) for voltage in voltage_str.split(',')]
        return voltage_out

    def dc_voltage_counts(self, counts=10, plc=0.02):
        # 等待 测量完成并将所有可用的测量结果复制到仪器的输出缓冲区
        self.device.write(f'CONF:VOLT:DC {plc},0.003')
        self.device.write('VOLT:DC:RANG:AUTO ON')  # 设置电压量程自动调整
        self.device.write('TRIG:SOUR BUS')  # 设置触发源为等待触发
        self.device.write(f'SAMP:COUN {counts}')  # 设置采样次数
        self.device.write('INIT')
        self.device.write('*TRG')
        time.sleep(0.1)
        voltage_str = self.device.query('FETC?')[:-1]  # 读取本次测量生成的测量值
        voltage_float = [float(vol) for vol in voltage_str.split(',')]
        print(np.mean(voltage_float))
        return np.mean(voltage_float)

    def measure_dc_current(self, wait_time=2):
        ret = self.device.query('MEAS:CURR:DC?')
        time.sleep(wait_time)
        current = float(ret.replace('\n', ''))
        return current

DEBUG = 0
def debugPrint(msg):
    if DEBUG:
        print(msg)

# IT8510
class IT8510():
    def __init__(self, comport) -> None:
        self.session = serial.Serial(comport, 9600, timeout=1)


    def getID(self):
        self.session.write(b'*ver\r\n')
        time.sleep(0.1)
        cnt = self.session.in_waiting
        ret = self.session.read(cnt)
        debugPrint(ret)

    def set_temp(self, temp):
        self.session.write(b's=%f\r\n' % temp)
        time.sleep(1)

    def set_sr(self, scanrate):
        self.session.write(b'sr=%d\r\n' % scanrate)
        time.sleep(1)

    def read_state(self):
        # 0 不稳定 1稳定
        self.session.write(b'st\r\n')
        time.sleep(0.1)
        cnt = self.session.in_waiting
        # ret = self.session.read(cnt).decode().split(':')[1].rstrip('\n')
        ret = self.session.read(cnt).decode().split(':')[1].rstrip('\n')
        # ret = self.session.read(cnt).decode()
        debugPrint(ret)
        return ret

# GHS_64
class GHS_64():
    def __init__(self, comport) -> None:
        self.session = serial.Serial(comport, 9600, timeout=0.5)
    def temp_read(self):
        """
        读取设备温度
        Returns:
        """
        self.session.write(b'TEMP?\n')
        time.sleep(0.5)
        cnt = self.session.in_waiting
        ret = self.session.read(cnt).decode().split(",")#.split(':')[1].rstrip('\n')
        debugPrint(ret[0])
        return ret[0]

    def read_current_HUMI(self):
        self.session.write(b'HUMI?\n')
        time.sleep(0.5)
        cnt = self.session.in_waiting
        ret = self.session.read(cnt).decode().split(",")#.split(':')[1].rstrip('\n')
        debugPrint(ret[0])
        return ret[0]
    def getID(self):
        self.session.write(b',*ver\r\n')
        time.sleep(0.1)
        cnt = self.session.in_waiting
        ret = self.session.read(cnt)
        debugPrint(ret)

    def set_temp(self, temp):
        self.session.write(b'TEMP S%f H100.0 L-40.0\n' % temp)
        time.sleep(0.1)
        cnt = self.session.in_waiting
        ret = self.session.read(cnt)
        debugPrint(ret)

    def set_humi(self, humi):
        self.session.write(b'HUMI S%f H100 L0\n' % humi)

    def read_current_MODE(self):
        self.session.write(b'MODE?\n')
        time.sleep(0.5)
        cnt = self.session.in_waiting
        ret = self.session.read(cnt).decode()  # .split(':')
        print(ret)
        return ret

    def write_power(self, start):
        if start == 1:
            self.session.write(b'POWER, ON')
        else:
            self.session.write(b'POWER, OFF')

    def date_read(self):
        self.session.write(b'DATE?\n')
        time.sleep(0.5)
        cnt = self.session.in_waiting
        ret = self.session.read(cnt).split(b'.')
        date = [ret[0]] + ret[1].split(b'/')
        year = int(date[0]) + 2000
        month=int(date[1])
        day=int(date[2])
        DATE = ('{0}-{1}-{2}').format(year, month, day)
        return DATE

    def close(self):
        try:
            self.session.close()
        except Exception:
            pass

    def temp_set(self, setpoint=25, maximum=110, minimum=-45):
        if setpoint is not None and minimum is not None and maximum is not None:
            (self.session.write[bytes('TEMP, S{0:.1f} H{0:.1f} L{0:.1f}'.format(setpoint, maximum, minimum))]).decode()
            #self.ctlr.interact('TEMP, S%0.1f H%0.1f L%0.1f' % (setpoint, maximum, minimum))
        else:
            if setpoint is not None:
                (self.session.write('TEMP, S{0:.1f}'.format(setpoint))).decode('utf-8', 'replace')
            if minimum is not None:
                (self.session.write('TEMP, L{0:.1f}'.format(minimum))).decode('utf-8', 'replace')
            if maximum is not None:
                (self.session.write('TEMP, H{0:.1f}'.format(maximum))).decode('utf-8', 'replace')

# LECROY_HD9000
class LECROY_HD9000():
    def __init__(self, ipaddr) -> None:
        self.session = vxi11.Instrument(ipaddr)

    def setOffset(self, chnn, ofst):
        """
        <channel>:= <C1 to Cn>
        <offset>:= <any valid value>
        """
        self.session.write('%s:OFFSET %sV' % (chnn, ofst))

    def setTimeDiv(self, tdiv):
        """
        <value>:= <any valid value>
        """
        self.session.write('TIME_DIV %E' % tdiv)

    def setTrigDelay(self, tdel):
        """
        <value>:= <any valid value>
        """
        self.session.write('TRIG_DELAY %E' % tdel)

    def setVoltDiv(self, chnn, vdiv):
        """
        <channel>:= <C1 to Cn>
        <v_gain>:= <any valid value><unit=V>
        """
        self.session.write('%s:VOLT_DIV %sV' % (chnn, vdiv))

    def setAutoMode(self):
        self.session.write('TRIG_MODE AUTO')

    def setNormalMode(self):
        self.session.write('TRIG_MODE Normal')

    def setSingleMode(self):
        self.session.write('TRIG_MODE SINGLE')

    def setStopMode(self):
        self.session.write('TRIG_MODE Stop')

    def getTrigMode(self):
        ret = self.session.ask('TRIG_MODE?')
        debugPrint(ret)
        return ret

    def setTrigTypeSrc(self, type, src):
        """
        type:DROP,EDGE,GLIT,INTV,PA,RUNT,SLEW,SQ,TEQ,TEQ1,SNG,STD
        src:C1,C2,Cn
        """
        self.session.write('TRIG_SELECT %s,SR,%s' % (type, src))

    def setTrigSlope(self, src, slope):
        """
        <trig_source>:= {C1, C2, C3, C4, LINE, EX, EX10, ETM10}
        <trig_slope>:= {NEG, POS}
        """
        self.session.write('%s:TRIG_SLOPE %s' % (src, slope))

    # def setTrigSlope(self, src, slope):
    #     """
    #     <trig_source>:= {C1, C2, C3, C4, LINE, EX, EX10, ETM10}
    #     <trig_slope>:= {NEG, POS}
    #     """
    #     self.session.write('%s:CURSOR_MEASURE %s' % (src, slope))

    def setTrigLevel(self, src, level):
        """
        <trig_source>:= <C1 to Cn, EX, EX10, ETM10>
        <trig_level>V
        """
        self.session.write('%s:TRIG_LEVEL %sV' % (src, level))

    def setDispOn(self, chnn):
        """
        <trace>:= C1 to Cn, F1 to Fn, TA to TD
        """
        self.session.write('%s:TRACE ON' % chnn)

    def setDispOff(self, chnn):
        """
        <trace>:= C1 to Cn, F1 to Fn, TA to TD
        """
        self.session.write('%s:TRACE OFF' % chnn)

    def setLabel(self, chnn, label: str):
        self.session.write('%s:TRACE_LABEL %s' % (chnn, label))

    def getParameterCustom(self, col):
        ret = self.session.ask('PACU? %s' % col)
        debugPrint(ret)
        return ret

    def deletePACU(self, col):
        self.session.write('PADL %s' % col)

    def setParameterCustom(self, col, meastyp, chnn):
        print('PACU %s,%s,C%s' % (col, meastyp, chnn))
        self.session.write('PACU %s,%s,C%s' % (col, meastyp, chnn))
        # print('PACU %s,%s,C%s' % (col, meastyp, chnn))

    def getValuePACU(self, meastyp, chnn):
        '''
        Frequency, Duty cycle:DUTY, Mean:MEAN
        '''
        ret = self.session.ask('C%s:PAVA? %s' % (chnn, meastyp))
        debugPrint(ret)
        if 'UNDEF' in ret.split(',')[1]:
            return 'UNDEF'
        else:
            # debugPrint(ret.split(',')[1].split(' ')[0])
            return float(ret.split(',')[1].split(' ')[0])

    def saveScreenImg(self, dirpath, filename):
        """
        HARDCOPY_SETUP DEV,<device>,FORMAT,<format>,BCKG,<bckg>,
        DEST,<destination>,DIR,"<directory>",AREA,<hardcopyarea>
        [,FILE,"<filename>",PRINTER,"<printername>",PORT,<portname>]
        <device>:= {BMP, JPEG, PNG, TIFF}
        <format>:= {PORTRAIT, LANDSCAPE}
        <bckg>:= {BLACK, WHITE}
        <destination>:= {PRINTER, CLIPBOARD, EMAIL, FILE, REMOTE}
        <area>:= {GRIDAREAONLY, DSOWINDOW, FULLSCREEN}
        <directory>:= legal DOS path, for FILE mode only
        <filename>:= filename string, no extension, for FILE mode only
        <printername>:= valid printer name, for PRINTER mode only
        <portname>:= {GPIB, NET}
        """
        self.session.write('HCSU DEV,PNG,FORMAT,PORTRAIT,BCKG,BLACK,DEST,FILE,DIR,"%s",AREA,GRIDAREAONLY,FILE,"%s"' % (
        dirpath, filename))
        self.session.ask('INR?')
        time.sleep(0.5)
        self.session.write('SCDP')

if __name__ == '__main__':
    rm = pyvisa.ResourceManager()
    device = Keysight34461A('TCPIP::169.254.4.61::INSTR')
    device.set_voltage(9)  # 设置输出电压为9V
    print(f"输出保存的值：{device.reset_id()}")
    print(f'当前电压值：{device.dc_voltage()[0]}')
    print(f'当前电流值：{device.measure_dc_current()}')
    print(f'当前电压值：{device.dc_voltage_counts()}')
